﻿using HARTCalibrationTool.Commands.BatchCalibrationBoard;
using HARTCalibrationTool.SerialPortManager;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace HARTCalibrationTool.Commands.TwoDimensionalCMDGroup
{
    public class CMDsGroup
    {
        private Queue<(CommandsBase, TimeSpan delay)> _commandsQueue = new Queue<(CommandsBase, TimeSpan delay)>();
        public int MaxRetries { get; set; } = 3;
        private CancellationTokenSource _cts;
        public CMDsChlID CurrentGroupChl { get; private set; } = CMDsChlID.eChannelNull;

        public CMDsGroup(CMDsChlID chl)
        {
            CurrentGroupChl = chl;
        }

        public void AddCommands(IEnumerable<(CommandsBase, TimeSpan delay)> commands)
        {
            foreach (var command in commands)
            {
                _commandsQueue.Enqueue(command);
            }
        }

        public async Task<bool> ExecuteGroupAsync(CancellationToken cancellationToken, bool isStopped, bool isStopAfTimeout)
        {
            SerialPortsBase serialPort = null;

            while (_commandsQueue.Count > 0 && !isStopped)
            { 
                var (command, delay) = _commandsQueue.Peek();
                serialPort = command.SerialPortMager;
                serialPort.SetCurrentCMD(command);
                serialPort.CommandCompleted += OnCommandCompleted;
                int retryCount = 0;
                bool isSuccess = false;

                while (retryCount <= MaxRetries)
                {
                    cancellationToken.ThrowIfCancellationRequested();

                    command.CurrentGroupChannel = this.CurrentGroupChl;
                    command.PrintMessage($"当前命令: Group-{command.CurrentGroupChannel}, {command.CommandName}");

                    _cts = new CancellationTokenSource();
                    var commandTask = command.ExecuteCMD();
                    var timeoutTask = Task.Delay(TimeSpan.FromSeconds(1.5), _cts.Token);

                    var completedTask = await Task.WhenAny(commandTask, timeoutTask);

                    if (completedTask == timeoutTask)
                    {
                        command.PrintMessage("Command:" + command.CommandName + ", 发送超时！");
                        serialPort.CommandCompleted -= OnCommandCompleted;
                        _commandsQueue.Clear();
                        break;
                    }
                    else
                    {
                        isSuccess = await WaitForResponseAsync(command, isStopAfTimeout);

                        if (isSuccess)
                        {
                            _commandsQueue.Dequeue();
                            if (_commandsQueue.Count == 0)
                            {
                                return true;
                            }

                            await Task.Delay(delay, cancellationToken);

                            break;
                        }
                        else
                        {
                            retryCount++;

                            if (retryCount >= MaxRetries)
                            {
                                _commandsQueue.Clear();

                                command.OnFailure();
                                LogFailure();

                                return false;
                            }
                        }
                    }
                }

                if (isStopped)
                {
                    command.PrintMessage("任务暂停！");
                    break;
                }
            }

            return false;
        }

        private async Task<bool> WaitForResponseAsync(CommandsBase command, bool isStopAfTimeout)
        {
            var tcs = new TaskCompletionSource<bool>();
            EventHandler handler = (s, e) => tcs.TrySetResult(true);
            SerialPortsBase serialPort = command.SerialPortMager;
            bool isSuccess = false;

            try
            {
                serialPort.CommandCompleted += handler;

                var timeoutTask = Task.Delay(TimeSpan.FromSeconds(5));
                var responseTask = tcs.Task;

                var completedTask = await Task.WhenAny(responseTask, timeoutTask);

                if (completedTask == timeoutTask)
                {
                    command.OnTimeout();
                    command.PrintMessage("Command:" + command.CommandName + ", 响应超时！");

                    if (!isStopAfTimeout)
                    {
                        return true;
                    }
                }
                else
                {
                    command.OnSuccess();
                    isSuccess = true;
                }
            }
            catch (Exception ex)
            {
                command.PrintMessage(ex.ToString());
            }
            finally
            {
                serialPort.CommandCompleted -= handler;
            }

            return isSuccess;
        }

        private void LogFailure()
        { 
        
        }

        public void AddCommand(CommandsBase command, TimeSpan delay)
        {
            _commandsQueue.Enqueue((command, delay));
        }
        private void OnCommandCompleted(object sender, EventArgs e)
        {
            // Notify that the command has completed and proceed to the next command
            _cts?.Cancel();
        }
    }
}
